package com.lry.thompson;

import com.lry.input.Input;

import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class DfaMachine {

    private Nfa start;

    private NfaInterpreter  nfaInterpreter;

    //假定DFA状态机节点数不会超过254个
    public static final int MAX_DFA_STATE_COUNT = 254;

    public static final int ASCII_COUNT = 128;

    public static final int STATE_FAILURE = -1;

    //使用二维数组表示DFA有限状态自动机
    private int[][] dfaStateTransformTable = new int[MAX_DFA_STATE_COUNT][ASCII_COUNT + 1];
    private Input input;

    public Input getInput() {
        return input;
    }

    public int[][] getDfaStateTransformTable() {
        return dfaStateTransformTable;
    }

    public DfaMachine(Nfa start, NfaInterpreter nfaInterpreter, Input input) {
        this.nfaInterpreter = nfaInterpreter;
        this.input = input;
        this.start = start;
        initTransformTable();
    }

    private void initTransformTable() {
        for (int i = 0; i < MAX_DFA_STATE_COUNT; i++){
            for (int j = 0; j <= ASCII_COUNT; j++) {
                dfaStateTransformTable[i][j] = STATE_FAILURE;
            }
        }
    }

    public void interpreter(){
        System.out.println("dfa Input string: ");
        input.renewInputBuffer();

        List<String> inputList = input.readInput();

        for(String str:inputList){
            int stateNum = DfaManager.start.stateNum;
            for (char c : str.toCharArray()) {
                if(stateNum==STATE_FAILURE){
                    System.out.println("The DFA Machine can not recognize string: " + str);
                    break;
                }
                stateNum = dfaStateTransformTable[stateNum][c];
            }

            if(stateNum==STATE_FAILURE){
                System.out.println("The DFA Machine can not recognize string: " + str);
            }else{
                boolean f = DfaManager.isEnd(stateNum);
                if(f){
                    System.out.println("The DFA Machine can recognize string: " + str);
                }else{
                    System.out.println("The DFA Machine can not recognize string: " + str);
                }
            }
        }
    }

    public void convertNfaToDfa(){
        System.out.println("\nnfa to dfa:");

        Set<Nfa> input = new HashSet<>();
        input.add(start);

        //计算nfa头节点的闭包
        Set<Nfa> nfaStartClosure = nfaInterpreter.εClosure(input);

        //nfa的同一个闭包中的节点共同构成一个dfa节点，如果闭包中包含终止节点，设置为终状态
        DfaManager.getDfa(nfaStartClosure);

        int nextState = STATE_FAILURE;
        while (!DfaManager.stack.isEmpty()) {
            Dfa currentDfa = DfaManager.stack.pop();

            //因为要计算dfaStateTransformTable 跳转表，所以遍历所有ascll码
            for (char c = 0; c <= ASCII_COUNT; c++) {

                //move = 闭包中的nfa节点碰到字符c可以到达哪些nfa节点
                Set<Nfa> move = nfaInterpreter.move(currentDfa.nfaSet, c);

                if (!move.isEmpty()) {
                    //计算闭包
                    Set<Nfa> closure = nfaInterpreter.εClosure(move);
                    Dfa dfa = DfaManager.getDfa(closure);
                    nextState = dfa.stateNum;
                }else {
                    //如果到达不了任何节点，则置跳转状态为 fail
                    nextState = STATE_FAILURE;
                }

                if (nextState != STATE_FAILURE&&ThompsonConstruction.print) {
                    System.out.println("DFA from state: " + currentDfa.stateNum + " to state:" + nextState + " on char: " + c);
                }
                dfaStateTransformTable[currentDfa.stateNum][c] = nextState;
            }
            if(ThompsonConstruction.print) {
                System.out.print("\n");
            }
        }
    }

}
